package exceptions

import (
	"encoding/json"
	"fmt"
	"github.com/gophercloud/gophercloud"
)

type StackError struct {
	Code        int    `json:"code"`
	Title       string `json:"title"`
	Explanation string `json:"explanation"`
	Error       Error  `json:"Error"`
}

type Error struct {
	Type      string `json:"type"`
	Traceback string `json:"traceback"`
	Message   string `json:"message"`
}

type StackErrorDetails StackError

// error types from provider_client.go
func StackExtractErrorInto(rawError error, errorDetails *StackErrorDetails) (err error, code int) {
	switch e := rawError.(type) {
	case gophercloud.ErrDefault400:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault401:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault403:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault404:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault405:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault408:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault409:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault429:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault500:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	case gophercloud.ErrDefault503:
		err = json.Unmarshal(e.ErrUnexpectedResponseCode.Body, errorDetails)
		code = e.Actual
	default:
		err = fmt.Errorf("Unable to extract detailed error message")
		code = 500
	}

	return
}

type SeverErrorBase struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

type ServerError struct {
	SeverErrorBase
}

type ServerErrorDetails ServerError

// error types from provider_client.go
func ServerExtractErrorInto(rawError error, errorDetails *ServerErrorDetails) (err map[string]interface{}, code int) {
	switch e := rawError.(type) {
	case gophercloud.ErrDefault400:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault401:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault403:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault404:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault405:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault408:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault409:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault429:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault500:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	case gophercloud.ErrDefault503:
		err = serverExtractError(e.ErrUnexpectedResponseCode.Body)
		code = e.Actual
	default:
		aa := make(map[string]interface{})
		aa["code"] = 500
		aa["message"] = "Unexcept Error, please contact administrotor"
		err["Unexcept Error"] = aa
		code = 500
	}

	return
}

func serverExtractError(body []byte) map[string]interface{} {
	m := make(map[string]interface{})
	err := json.Unmarshal(body, &m)
	if err != nil {
		fmt.Println(err)
	}
	return m
}
